<template>
  <div class="container">
    <!-- 头部信息栏 -->
    <HeaderStats 
      :earthquakeCount="earthquakeCount"
      :maxMagnitude="maxMagnitude"
      :lastUpdate="lastUpdate"
    />

    <!-- 地图容器 -->
    <div class="map-container">
      <div id="map" ref="mapContainer"></div>
      
      <!-- 图例 -->
      <MagnitudeLegend />

      <!-- 加载指示器 -->
      <LoadingSpinner v-if="isLoading" />
    </div>

    <!-- 控制面板 -->
    <ControlPanel 
      :isAutoRefresh="isAutoRefresh"
      :currentFilter="currentFilter"
      @refresh="loadEarthquakeData"
      @toggleAutoRefresh="toggleAutoRefresh"
      @filterChange="handleFilterChange"
    />
  </div>
</template>

<script>
import { ref, onMounted, onUnmounted } from 'vue'
import L from 'leaflet'
import HeaderStats from './components/HeaderStats.vue'
import MagnitudeLegend from './components/MagnitudeLegend.vue'
import LoadingSpinner from './components/LoadingSpinner.vue'
import ControlPanel from './components/ControlPanel.vue'

export default {
  name: 'EarthquakeMonitor',
  components: {
    HeaderStats,
    MagnitudeLegend,
    LoadingSpinner,
    ControlPanel
  },
  setup() {
    // 响应式数据
    const mapContainer = ref(null)
    const map = ref(null)
    const earthquakeLayer = ref(null)
    const isLoading = ref(false)
    const isAutoRefresh = ref(false)
    const currentFilter = ref('all')
    const earthquakeData = ref([])
    const earthquakeCount = ref(0)
    const maxMagnitude = ref(0)
    const lastUpdate = ref('')
    const autoRefreshInterval = ref(null)

    // 初始化地图
    const initMap = () => {
      map.value = L.map(mapContainer.value, {
        center: [20, 0],
        zoom: 2,
        zoomControl: true,
        attributionControl: true
      })

      L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
        attribution: '© OpenStreetMap contributors | 地震数据来源: USGS',
        maxZoom: 18
      }).addTo(map.value)

      earthquakeLayer.value = L.layerGroup().addTo(map.value)
    }

    // 获取地震数据
    const loadEarthquakeData = async () => {
      isLoading.value = true
      try {
        const response = await fetch('https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_day.geojson')
        const data = await response.json()
        
        earthquakeData.value = data.features
        displayEarthquakes()
        updateStats()
        
      } catch (error) {
        console.error('加载地震数据失败:', error)
        showError('无法加载地震数据，请检查网络连接')
      } finally {
        isLoading.value = false
      }
    }

    // 显示地震标记
    const displayEarthquakes = () => {
      earthquakeLayer.value.clearLayers()

      earthquakeData.value.forEach(earthquake => {
        const coords = earthquake.geometry.coordinates
        const props = earthquake.properties
        
        const lat = coords[1]
        const lng = coords[0]
        const magnitude = props.mag
        
        if (!magnitude || magnitude < 0) return

        const markerStyle = getMarkerStyle(magnitude)
        const marker = L.circleMarker([lat, lng], markerStyle)
        
        const popupContent = createPopupContent(props, coords)
        marker.bindPopup(popupContent)
        
        earthquakeLayer.value.addLayer(marker)
      })

      filterEarthquakes()
    }

    // 获取标记样式
    const getMarkerStyle = (magnitude) => {
      let color, fillColor, radius

      if (magnitude < 3.0) {
        color = '#48bb78'
        fillColor = '#48bb78'
        radius = 4
      } else if (magnitude < 4.0) {
        color = '#38b2ac'
        fillColor = '#38b2ac'
        radius = 6
      } else if (magnitude < 5.0) {
        color = '#4299e1'
        fillColor = '#4299e1'
        radius = 8
      } else if (magnitude < 6.0) {
        color = '#ed8936'
        fillColor = '#ed8936'
        radius = 12
      } else if (magnitude < 7.0) {
        color = '#f56565'
        fillColor = '#f56565'
        radius = 16
      } else {
        color = '#9f1239'
        fillColor = '#9f1239'
        radius = 20
      }

      return {
        color: color,
        fillColor: fillColor,
        fillOpacity: 0.7,
        weight: 2,
        radius: radius
      }
    }

    // 创建弹窗内容
    const createPopupContent = (props, coords) => {
      const magnitude = props.mag || 0
      const place = props.place || '未知地点'
      const time = new Date(props.time).toLocaleString('zh-CN')
      const depth = coords[2] || 0
      const url = props.url
      
      const magnitudeColor = getMagnitudeColor(magnitude)
      
      return `
        <div class="popup-content">
          <div class="popup-title">🌍 地震信息</div>
          <div class="popup-info">
            <div class="popup-row">
              <span class="popup-label">地点:</span>
              <span class="popup-value">${place}</span>
            </div>
            <div class="popup-row">
              <span class="popup-label">震级:</span>
              <span class="magnitude-badge" style="background-color: ${magnitudeColor}">
                M ${magnitude.toFixed(1)}
              </span>
            </div>
            <div class="popup-row">
              <span class="popup-label">深度:</span>
              <span class="popup-value">${depth.toFixed(1)} km</span>
            </div>
            <div class="popup-row">
              <span class="popup-label">时间:</span>
              <span class="popup-value">${time}</span>
            </div>
            <div class="popup-row">
              <span class="popup-label">坐标:</span>
              <span class="popup-value">${coords[1].toFixed(3)}°, ${coords[0].toFixed(3)}°</span>
            </div>
            ${url ? `<div class="popup-row">
              <a href="${url}" target="_blank" style="color: #4299e1; text-decoration: none; font-weight: 500;">
                📊 查看详细信息
              </a>
            </div>` : ''}
          </div>
        </div>
      `
    }

    // 获取震级颜色
    const getMagnitudeColor = (magnitude) => {
      if (magnitude < 3.0) return '#48bb78'
      if (magnitude < 4.0) return '#38b2ac'
      if (magnitude < 5.0) return '#4299e1'
      if (magnitude < 6.0) return '#ed8936'
      if (magnitude < 7.0) return '#f56565'
      return '#9f1239'
    }

    // 筛选地震
    const filterEarthquakes = () => {
      earthquakeLayer.value.eachLayer(layer => {
        const magnitude = getMagnitudeFromLayer(layer)
        let show = true

        switch (currentFilter.value) {
          case 'significant':
            show = magnitude >= 4.5
            break
          case 'major':
            show = magnitude >= 6.0
            break
          default:
            show = true
        }

        if (show) {
          layer.setStyle({ opacity: 1, fillOpacity: 0.7 })
        } else {
          layer.setStyle({ opacity: 0.3, fillOpacity: 0.1 })
        }
      })
    }

    // 从图层获取震级
    const getMagnitudeFromLayer = (layer) => {
      const radius = layer.options.radius
      if (radius <= 4) return 2.5
      if (radius <= 6) return 3.5
      if (radius <= 8) return 4.5
      if (radius <= 12) return 5.5
      if (radius <= 16) return 6.5
      return 7.5
    }

    // 更新统计信息
    const updateStats = () => {
      earthquakeCount.value = earthquakeData.value.length
      maxMagnitude.value = Math.max(...earthquakeData.value.map(eq => eq.properties.mag || 0))
      lastUpdate.value = new Date().toLocaleString('zh-CN')
    }

    // 切换自动刷新
    const toggleAutoRefresh = () => {
      if (isAutoRefresh.value) {
        clearInterval(autoRefreshInterval.value)
        isAutoRefresh.value = false
      } else {
        autoRefreshInterval.value = setInterval(() => {
          loadEarthquakeData()
        }, 5 * 60 * 1000)
        isAutoRefresh.value = true
      }
    }

    // 处理筛选变化
    const handleFilterChange = (filter) => {
      currentFilter.value = filter
      filterEarthquakes()
    }

    // 显示错误信息
    const showError = (message) => {
      // 这里可以使用Vue的通知组件或者简单的alert
      alert(message)
    }

    // 生命周期钩子
    onMounted(() => {
      initMap()
      loadEarthquakeData()
    })

    onUnmounted(() => {
      if (autoRefreshInterval.value) {
        clearInterval(autoRefreshInterval.value)
      }
    })

    return {
      mapContainer,
      isLoading,
      isAutoRefresh,
      currentFilter,
      earthquakeCount,
      maxMagnitude,
      lastUpdate,
      loadEarthquakeData,
      toggleAutoRefresh,
      handleFilterChange
    }
  }
}
</script>
</template>
</write_to_file>

<write_to_file>
<path>earthquake-monitor-v2/src/style.css</path>
<content>
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    min-height: 100vh;
    color: #333;
}

.container {
    max-width: 100vw;
    height: 100vh;
    display: flex;
    flex-direction: column;
}

/* 地图容器 */
.map-container {
    flex: 1;
    position: relative;
    margin: 1rem;
    border-radius: 12px;
    overflow: hidden;
    box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
}

#map {
    height: 100%;
    width: 100%;
}

/* 弹窗样式 */
.leaflet-popup-content-wrapper {
    background: rgba(255, 255, 255, 0.95);
    backdrop-filter: blur(10px);
    border-radius: 12px;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
}

.leaflet-popup-content {
    margin: 1rem;
    font-family: 'Inter', sans-serif;
}

.popup-title {
    font-size: 1.1rem;
    font-weight: 700;
    color: #2d3748;
    margin-bottom: 0.75rem;
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.popup-info {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.popup-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0.25rem 0;
    border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}

.popup-row:last-child {
    border-bottom: none;
}

.popup-label {
    font-weight: 500;
    color: #4a5568;
    font-size: 0.9rem;
}

.popup-value {
    font-weight: 600;
    color: #2d3748;
    font-size: 0.9rem;
}

.magnitude-badge {
    padding: 0.25rem 0.75rem;
    border-radius: 20px;
    color: white;
    font-weight: 700;
    font-size: 0.8rem;
}

/* 响应式设计 */
@media (max-width: 768px) {
    .map-container {
        margin: 0.5rem;
    }
}

@media (max-width: 480px) {
    .map-container {
        margin: 0.25rem;
    }
}